/******************************************************************************* * Copyright (c) 2000, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.jdt.internal.corext.refactoring; import java.util.ArrayList; import java.util.List; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourceAttributes; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.resources.mapping.IResourceChangeDescriptionFactory; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.core.refactoring.participants.CheckConditionsContext; import org.eclipse.ltk.core.refactoring.participants.ResourceChangeChecker; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaModelMarker; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.ILocalVariable; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.AnonymousClassDeclaration; import org.eclipse.jdt.core.dom.Expression; import org.eclipse.jdt.core.dom.IBinding; import org.eclipse.jdt.core.dom.IMethodBinding; import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.IVariableBinding; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.SwitchCase; import org.eclipse.jdt.core.dom.VariableDeclaration; import org.eclipse.jdt.internal.corext.Corext; import org.eclipse.jdt.internal.corext.dom.ASTNodes; import org.eclipse.jdt.internal.corext.dom.Bindings; import org.eclipse.jdt.internal.corext.refactoring.base.JavaStatusContext; import org.eclipse.jdt.internal.corext.refactoring.base.RefactoringStatusCodes; import org.eclipse.jdt.internal.corext.refactoring.util.JavaElementUtil; import org.eclipse.jdt.internal.corext.util.JavaConventionsUtil; import org.eclipse.jdt.internal.corext.util.JavaModelUtil; import org.eclipse.jdt.internal.corext.util.JdtFlags; import org.eclipse.jdt.internal.corext.util.Messages; import org.eclipse.jdt.internal.corext.util.Resources; import org.eclipse.jdt.ui.JavaElementLabels; import org.eclipse.jdt.internal.ui.text.correction.ASTResolving; import org.eclipse.jdt.internal.ui.viewsupport.BasicElementLabels; /** * This class defines a set of reusable static checks methods. */ public class Checks { /* * no instances */ private Checks(){ } /* Constants returned by checkExpressionIsRValue */ public static final int IS_RVALUE= 0; public static final int NOT_RVALUE_MISC= 1; public static final int NOT_RVALUE_VOID= 2; /** * @since 3.6 */ public static final int IS_RVALUE_GUESSED= 3; /** * Checks if method will have a constructor name after renaming. * @param method * @param newMethodName * @param newTypeName * @return <code>RefactoringStatus</code> with <code>WARNING</code> severity if * the give method will have a constructor name after renaming * <code>null</code> otherwise. */ public static RefactoringStatus checkIfConstructorName(IMethod method, String newMethodName, String newTypeName){ if (! newMethodName.equals(newTypeName)) return null; else return RefactoringStatus.createWarningStatus( Messages.format(RefactoringCoreMessages.Checks_constructor_name, new Object[] {JavaElementUtil.createMethodSignature(method), JavaElementLabels.getElementLabel(method.getDeclaringType(), JavaElementLabels.ALL_FULLY_QUALIFIED) } )); } /** * Checks if the given name is a valid Java field name. * * @param name the java field name. * @param context an {@link IJavaElement} or <code>null</code> * @return a refactoring status containing the error message if the * name is not a valid java field name. */ public static RefactoringStatus checkFieldName(String name, IJavaElement context) { return checkName(name, JavaConventionsUtil.validateFieldName(name, context)); } /** * Checks if the given name is a valid Java type parameter name. * * @param name the java type parameter name. * @param context an {@link IJavaElement} or <code>null</code> * @return a refactoring status containing the error message if the * name is not a valid java type parameter name. */ public static RefactoringStatus checkTypeParameterName(String name, IJavaElement context) { return checkName(name, JavaConventionsUtil.validateTypeVariableName(name, context)); } /** * Checks if the given name is a valid Java identifier. * * @param name the java identifier. * @param context an {@link IJavaElement} or <code>null</code> * @return a refactoring status containing the error message if the * name is not a valid java identifier. */ public static RefactoringStatus checkIdentifier(String name, IJavaElement context) { return checkName(name, JavaConventionsUtil.validateIdentifier(name, context)); } /** * Checks if the given name is a valid Java method name. * * @param name the java method name. * @param context an {@link IJavaElement} or <code>null</code> * @return a refactoring status containing the error message if the * name is not a valid java method name. */ public static RefactoringStatus checkMethodName(String name, IJavaElement context) { RefactoringStatus status= checkName(name, JavaConventionsUtil.validateMethodName(name, context)); if (status.isOK() && startsWithUpperCase(name)) return RefactoringStatus.createWarningStatus(RefactoringCoreMessages.Checks_method_names_lowercase); else return status; } /** * Checks if the given name is a valid Java type name. * * @param name the java method name. * @param context an {@link IJavaElement} or <code>null</code> * @return a refactoring status containing the error message if the * name is not a valid java type name. */ public static RefactoringStatus checkTypeName(String name, IJavaElement context) { //fix for: 1GF5Z0Z: ITPJUI:WINNT - assertion failed after renameType refactoring if (name.indexOf(".") != -1) //$NON-NLS-1$ return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.Checks_no_dot); else return checkName(name, JavaConventionsUtil.validateJavaTypeName(name, context)); } /** * Checks if the given name is a valid Java package name. * * @param name the java package name. * @param context an {@link IJavaElement} or <code>null</code> * @return a refactoring status containing the error message if the * name is not a valid java package name. */ public static RefactoringStatus checkPackageName(String name, IJavaElement context) { return checkName(name, JavaConventionsUtil.validatePackageName(name, context)); } /** * Checks if the given name is a valid compilation unit name. * * @param name the compilation unit name. * @param context an {@link IJavaElement} or <code>null</code> * @return a refactoring status containing the error message if the * name is not a valid compilation unit name. */ public static RefactoringStatus checkCompilationUnitName(String name, IJavaElement context) { return checkName(name, JavaConventionsUtil.validateCompilationUnitName(name, context)); } /** * Returns ok status if the new name is ok. This is when no other file with that name exists. * @param cu * @param newName * @return the status */ public static RefactoringStatus checkCompilationUnitNewName(ICompilationUnit cu, String newName) { String newCUName= JavaModelUtil.getRenamedCUName(cu, newName); IPath renamedResourcePath= cu.getParent().getPath().append(newCUName); if (resourceExists(renamedResourcePath)) return RefactoringStatus.createFatalErrorStatus(Messages.format(RefactoringCoreMessages.Checks_cu_name_used, BasicElementLabels.getResourceName(newCUName))); else return new RefactoringStatus(); } public static boolean startsWithUpperCase(String s) { if (s == null) return false; else if ("".equals(s)) //$NON-NLS-1$ return false; else //workaround for JDK bug (see 26529) return s.charAt(0) == Character.toUpperCase(s.charAt(0)); } public static boolean startsWithLowerCase(String s){ if (s == null) return false; else if ("".equals(s)) //$NON-NLS-1$ return false; else //workaround for JDK bug (see 26529) return s.charAt(0) == Character.toLowerCase(s.charAt(0)); } public static boolean resourceExists(IPath resourcePath){ return ResourcesPlugin.getWorkspace().getRoot().findMember(resourcePath) != null; } public static boolean isTopLevel(IType type){ return type.getDeclaringType() == null; } public static boolean isAnonymous(IType type) throws JavaModelException { return type.isAnonymous(); } public static boolean isTopLevelType(IMember member){ return member.getElementType() == IJavaElement.TYPE && isTopLevel((IType) member); } public static boolean isInsideLocalType(IType type) throws JavaModelException { while (type != null) { if (type.isLocal()) return true; type= type.getDeclaringType(); } return false; } public static boolean isAlreadyNamed(IJavaElement element, String name){ return name.equals(element.getElementName()); } //-------------- main and native method checks ------------------ public static RefactoringStatus checkForMainAndNativeMethods(ICompilationUnit cu) throws JavaModelException { return checkForMainAndNativeMethods(cu.getTypes()); } public static RefactoringStatus checkForMainAndNativeMethods(IType[] types) throws JavaModelException { RefactoringStatus result= new RefactoringStatus(); for (int i= 0; i < types.length; i++) result.merge(checkForMainAndNativeMethods(types[i])); return result; } public static RefactoringStatus checkForMainAndNativeMethods(IType type) throws JavaModelException { RefactoringStatus result= new RefactoringStatus(); result.merge(checkForMainAndNativeMethods(type.getMethods())); result.merge(checkForMainAndNativeMethods(type.getTypes())); return result; } private static RefactoringStatus checkForMainAndNativeMethods(IMethod[] methods) throws JavaModelException { RefactoringStatus result= new RefactoringStatus(); for (int i= 0; i < methods.length; i++) { if (JdtFlags.isNative(methods[i])){ String typeName= JavaElementLabels.getElementLabel(methods[i].getDeclaringType(), JavaElementLabels.ALL_FULLY_QUALIFIED); String methodName= JavaElementLabels.getElementLabel(methods[i], JavaElementLabels.ALL_DEFAULT); String msg= Messages.format(RefactoringCoreMessages.Checks_method_native, new String[]{typeName, methodName, "UnsatisfiedLinkError"});//$NON-NLS-1$ result.addEntry(RefactoringStatus.ERROR, msg, JavaStatusContext.create(methods[i]), Corext.getPluginId(), RefactoringStatusCodes.NATIVE_METHOD); } if (methods[i].isMainMethod()) { String msg= Messages.format(RefactoringCoreMessages.Checks_has_main, JavaElementLabels.getElementLabel(methods[i].getDeclaringType(), JavaElementLabels.ALL_FULLY_QUALIFIED)); result.addEntry(RefactoringStatus.WARNING, msg, JavaStatusContext.create(methods[i]), Corext.getPluginId(), RefactoringStatusCodes.MAIN_METHOD); } } return result; } //---- New method name checking ------------------------------------------------------------- /** * Checks if the new method is already used in the given type. * @param type * @param methodName * @param parameters * @return the status */ public static RefactoringStatus checkMethodInType(ITypeBinding type, String methodName, ITypeBinding[] parameters) { RefactoringStatus result= new RefactoringStatus(); if (methodName.equals(type.getName())) result.addWarning(RefactoringCoreMessages.Checks_methodName_constructor); IMethodBinding method= org.eclipse.jdt.internal.corext.dom.Bindings.findMethodInType(type, methodName, parameters); if (method != null) result.addError(Messages.format(RefactoringCoreMessages.Checks_methodName_exists, new Object[] {BasicElementLabels.getJavaElementName(methodName), BasicElementLabels.getJavaElementName(type.getName())}), JavaStatusContext.create(method)); return result; } /** * Checks if the new method somehow conflicts with an already existing method in * the hierarchy. The following checks are done: * <ul> * <li> if the new method overrides a method defined in the given type or in one of its * super classes. </li> * </ul> * @param type * @param methodName * @param returnType * @param parameters * @return the status */ public static RefactoringStatus checkMethodInHierarchy(ITypeBinding type, String methodName, ITypeBinding returnType, ITypeBinding[] parameters) { RefactoringStatus result= new RefactoringStatus(); IMethodBinding method= Bindings.findMethodInHierarchy(type, methodName, parameters); if (method != null) { boolean returnTypeClash= false; ITypeBinding methodReturnType= method.getReturnType(); if (returnType != null && methodReturnType != null) { String returnTypeKey= returnType.getKey(); String methodReturnTypeKey= methodReturnType.getKey(); if (returnTypeKey == null && methodReturnTypeKey == null) { returnTypeClash= returnType != methodReturnType; } else if (returnTypeKey != null && methodReturnTypeKey != null) { returnTypeClash= !returnTypeKey.equals(methodReturnTypeKey); } } ITypeBinding dc= method.getDeclaringClass(); if (returnTypeClash) { result.addError(Messages.format(RefactoringCoreMessages.Checks_methodName_returnTypeClash, new Object[] {BasicElementLabels.getJavaElementName(methodName), BasicElementLabels.getJavaElementName(dc.getName())}), JavaStatusContext.create(method)); } else { result.addError(Messages.format(RefactoringCoreMessages.Checks_methodName_overrides, new Object[] {BasicElementLabels.getJavaElementName(methodName), BasicElementLabels.getJavaElementName(dc.getName())}), JavaStatusContext.create(method)); } } return result; } //---- Selection checks -------------------------------------------------------------------- public static boolean isExtractableExpression(ASTNode[] selectedNodes, ASTNode coveringNode) { ASTNode node= coveringNode; if (isEnumCase(node)) return false; if (selectedNodes != null && selectedNodes.length == 1) node= selectedNodes[0]; return isExtractableExpression(node); } public static boolean isEnumCase(ASTNode node) { if (node instanceof SwitchCase) { final SwitchCase caze= (SwitchCase) node; final Expression expression= caze.getExpression(); if (expression instanceof Name) { final Name name= (Name) expression; final IBinding binding= name.resolveBinding(); if (binding instanceof IVariableBinding) { IVariableBinding variableBinding= (IVariableBinding) binding; return variableBinding.isEnumConstant(); } } } return false; } public static boolean isExtractableExpression(ASTNode node) { if (!(node instanceof Expression)) return false; if (node instanceof Name) { IBinding binding= ((Name) node).resolveBinding(); return !(binding instanceof ITypeBinding); } return true; } public static boolean isInsideJavadoc(ASTNode node) { do { if (node.getNodeType() == ASTNode.JAVADOC) return true; node= node.getParent(); } while (node != null); return false; } /** * Returns a fatal error in case the name is empty. In all other cases, an * error based on the given status is returned. * * @param name a name * @param status a status * @return RefactoringStatus based on the given status or the name, if * empty. */ public static RefactoringStatus checkName(String name, IStatus status) { RefactoringStatus result= new RefactoringStatus(); if ("".equals(name)) //$NON-NLS-1$ return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.Checks_Choose_name); if (status.isOK()) return result; switch (status.getSeverity()){ case IStatus.ERROR: return RefactoringStatus.createFatalErrorStatus(status.getMessage()); case IStatus.WARNING: return RefactoringStatus.createWarningStatus(status.getMessage()); case IStatus.INFO: return RefactoringStatus.createInfoStatus(status.getMessage()); default: //no nothing return new RefactoringStatus(); } } /** * Finds a method in a type * This searches for a method with the same name and signature. Parameter types are only * compared by the simple name, no resolving for the fully qualified type name is done * @param name * @param parameterCount * @param isConstructor * @param type * @return The first found method or null, if nothing found * @throws JavaModelException */ public static IMethod findMethod(String name, int parameterCount, boolean isConstructor, IType type) throws JavaModelException { return findMethod(name, parameterCount, isConstructor, type.getMethods()); } /** * Finds a method in a type. * Searches for a method with the same name and the same parameter count. * Parameter types are <b>not</b> compared. * @param method * @param type * @return The first found method or null, if nothing found * @throws JavaModelException */ public static IMethod findMethod(IMethod method, IType type) throws JavaModelException { return findMethod(method.getElementName(), method.getParameterTypes().length, method.isConstructor(), type.getMethods()); } /** * Finds a method in an array of methods. * Searches for a method with the same name and the same parameter count. * Parameter types are <b>not</b> compared. * @param method * @param methods * @return The first found method or null, if nothing found * @throws JavaModelException */ public static IMethod findMethod(IMethod method, IMethod[] methods) throws JavaModelException { return findMethod(method.getElementName(), method.getParameterTypes().length, method.isConstructor(), methods); } public static IMethod findMethod(String name, int parameters, boolean isConstructor, IMethod[] methods) throws JavaModelException { for (int i= methods.length-1; i >= 0; i--) { IMethod curr= methods[i]; if (name.equals(curr.getElementName())) { if (isConstructor == curr.isConstructor()) { if (parameters == curr.getParameterTypes().length) { return curr; } } } } return null; } /** * Finds a method in a type. * This searches for a method with the same name and signature. Parameter types are only * compared by the simple name, no resolving for the fully qualified type name is done * @param method * @param type * @return The first found method or null, if nothing found * @throws JavaModelException */ public static IMethod findSimilarMethod(IMethod method, IType type) throws JavaModelException { return findSimilarMethod(method, type.getMethods()); } /** * Finds a method in an array of methods. * This searches for a method with the same name and signature. Parameter types are only * compared by the simple name, no resolving for the fully qualified type name is done * @param method * @param methods * @return The first found method or null, if nothing found * @throws JavaModelException */ public static IMethod findSimilarMethod(IMethod method, IMethod[] methods) throws JavaModelException { boolean isConstructor= method.isConstructor(); for (int i= 0; i < methods.length; i++) { IMethod otherMethod= methods[i]; if (otherMethod.isConstructor() == isConstructor && method.isSimilar(otherMethod)) return otherMethod; } return null; } /* * Compare two parameter signatures */ public static boolean compareParamTypes(String[] paramTypes1, String[] paramTypes2) { if (paramTypes1.length == paramTypes2.length) { int i= 0; while (i < paramTypes1.length) { String t1= Signature.getSimpleName(Signature.toString(paramTypes1[i])); String t2= Signature.getSimpleName(Signature.toString(paramTypes2[i])); if (!t1.equals(t2)) { return false; } i++; } return true; } return false; } //--------------------- public static RefactoringStatus checkIfCuBroken(IMember member) throws JavaModelException{ ICompilationUnit cu= (ICompilationUnit)JavaCore.create(member.getCompilationUnit().getResource()); if (cu == null) return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.Checks_cu_not_created); else if (! cu.isStructureKnown()) return RefactoringStatus.createFatalErrorStatus(RefactoringCoreMessages.Checks_cu_not_parsed); return new RefactoringStatus(); } /** * From SearchResultGroup[] passed as the parameter * this method removes all those that correspond to a non-parsable ICompilationUnit * and returns it as a result. * @param grouped the array of search result groups from which non parsable compilation * units are to be removed. * @param status a refactoring status to collect errors and problems * @return the array of search result groups * @throws JavaModelException */ public static SearchResultGroup[] excludeCompilationUnits(SearchResultGroup[] grouped, RefactoringStatus status) throws JavaModelException{ List result= new ArrayList(); boolean wasEmpty= grouped.length == 0; for (int i= 0; i < grouped.length; i++){ IResource resource= grouped[i].getResource(); IJavaElement element= JavaCore.create(resource); if (! (element instanceof ICompilationUnit)) continue; //XXX this is a workaround for a jcore feature that shows errors in cus only when you get the original element ICompilationUnit cu= (ICompilationUnit)JavaCore.create(resource); if (! cu.isStructureKnown()){ status.addError(Messages.format(RefactoringCoreMessages.Checks_cannot_be_parsed, BasicElementLabels.getPathLabel(cu.getPath(), false))); continue; //removed, go to the next one } result.add(grouped[i]); } if ((!wasEmpty) && result.isEmpty()) status.addFatalError(RefactoringCoreMessages.Checks_all_excluded); return (SearchResultGroup[])result.toArray(new SearchResultGroup[result.size()]); } public static RefactoringStatus checkCompileErrorsInAffectedFiles(SearchResultGroup[] grouped) throws JavaModelException { RefactoringStatus result= new RefactoringStatus(); for (int i= 0; i < grouped.length; i++) checkCompileErrorsInAffectedFile(result, grouped[i].getResource()); return result; } public static void checkCompileErrorsInAffectedFile(RefactoringStatus result, IResource resource) throws JavaModelException { if (hasCompileErrors(resource)) result.addWarning(Messages.format(RefactoringCoreMessages.Checks_cu_has_compile_errors, BasicElementLabels.getPathLabel(resource.getFullPath(), false))); } public static RefactoringStatus checkCompileErrorsInAffectedFiles(SearchResultGroup[] references, IResource declaring) throws JavaModelException { RefactoringStatus result= new RefactoringStatus(); for (int i= 0; i < references.length; i++){ IResource resource= references[i].getResource(); if (resource.equals(declaring)) declaring= null; checkCompileErrorsInAffectedFile(result, resource); } if (declaring != null) checkCompileErrorsInAffectedFile(result, declaring); return result; } private static boolean hasCompileErrors(IResource resource) throws JavaModelException { try { IMarker[] problemMarkers= resource.findMarkers(IJavaModelMarker.JAVA_MODEL_PROBLEM_MARKER, true, IResource.DEPTH_INFINITE); for (int i= 0; i < problemMarkers.length; i++) { if (problemMarkers[i].getAttribute(IMarker.SEVERITY, -1) == IMarker.SEVERITY_ERROR) return true; } return false; } catch (JavaModelException e){ throw e; } catch (CoreException e){ throw new JavaModelException(e); } } //------ public static boolean isReadOnly(Object element) throws JavaModelException{ if (element instanceof IResource) return isReadOnly((IResource)element); if (element instanceof IJavaElement) { if ((element instanceof IPackageFragmentRoot) && isClasspathDelete((IPackageFragmentRoot)element)) return false; return isReadOnly(((IJavaElement)element).getResource()); } Assert.isTrue(false, "not expected to get here"); //$NON-NLS-1$ return false; } public static boolean isReadOnly(IResource res) throws JavaModelException { ResourceAttributes attributes= res.getResourceAttributes(); if (attributes != null && attributes.isReadOnly()) return true; if (! (res instanceof IContainer)) return false; IContainer container= (IContainer)res; try { IResource[] children= container.members(); for (int i= 0; i < children.length; i++) { if (isReadOnly(children[i])) return true; } return false; } catch (JavaModelException e){ throw e; } catch (CoreException e) { throw new JavaModelException(e); } } public static boolean isClasspathDelete(IPackageFragmentRoot pkgRoot) { IResource res= pkgRoot.getResource(); if (res == null) return true; IProject definingProject= res.getProject(); if (res.getParent() != null && pkgRoot.isArchive() && ! res.getParent().equals(definingProject)) return true; IProject occurringProject= pkgRoot.getJavaProject().getProject(); return !definingProject.equals(occurringProject); } //-------- validateEdit checks ---- public static RefactoringStatus validateModifiesFiles(IFile[] filesToModify, Object context) { RefactoringStatus result= new RefactoringStatus(); IStatus status= Resources.checkInSync(filesToModify); if (!status.isOK()) result.merge(RefactoringStatus.create(status)); status= Resources.makeCommittable(filesToModify, context); if (!status.isOK()) { result.merge(RefactoringStatus.create(status)); if (!result.hasFatalError()) { result.addFatalError(RefactoringCoreMessages.Checks_validateEdit); } } return result; } public static void addModifiedFilesToChecker(IFile[] filesToModify, CheckConditionsContext context) { ResourceChangeChecker checker= (ResourceChangeChecker) context.getChecker(ResourceChangeChecker.class); IResourceChangeDescriptionFactory deltaFactory= checker.getDeltaFactory(); for (int i= 0; i < filesToModify.length; i++) { deltaFactory.change(filesToModify[i]); } } public static RefactoringStatus validateEdit(ICompilationUnit unit, Object context) { IResource resource= unit.getPrimary().getResource(); RefactoringStatus result= new RefactoringStatus(); if (resource == null) return result; IStatus status= Resources.checkInSync(resource); if (!status.isOK()) result.merge(RefactoringStatus.create(status)); status= Resources.makeCommittable(resource, context); if (!status.isOK()) { result.merge(RefactoringStatus.create(status)); if (!result.hasFatalError()) { result.addFatalError(RefactoringCoreMessages.Checks_validateEdit); } } return result; } /** * Checks whether it is possible to modify the given <code>IJavaElement</code>. * The <code>IJavaElement</code> must exist and be non read-only to be modifiable. * Moreover, if it is a <code>IMember</code> it must not be binary. * The returned <code>RefactoringStatus</code> has <code>ERROR</code> severity if * it is not possible to modify the element. * @param javaElement * @return the status * @throws JavaModelException * * @see IJavaElement#exists * @see IJavaElement#isReadOnly * @see IMember#isBinary * @see RefactoringStatus */ public static RefactoringStatus checkAvailability(IJavaElement javaElement) throws JavaModelException{ RefactoringStatus result= new RefactoringStatus(); if (! javaElement.exists()) result.addFatalError(Messages.format(RefactoringCoreMessages.Refactoring_not_in_model, getJavaElementName(javaElement))); if (javaElement.isReadOnly()) result.addFatalError(Messages.format(RefactoringCoreMessages.Refactoring_read_only, getJavaElementName(javaElement))); if (javaElement.exists() && !javaElement.isStructureKnown()) result.addFatalError(Messages.format(RefactoringCoreMessages.Refactoring_unknown_structure, getJavaElementName(javaElement))); if (javaElement instanceof IMember && ((IMember)javaElement).isBinary()) result.addFatalError(Messages.format(RefactoringCoreMessages.Refactoring_binary, getJavaElementName(javaElement))); return result; } private static String getJavaElementName(IJavaElement element) { return JavaElementLabels.getElementLabel(element, JavaElementLabels.ALL_DEFAULT); } public static boolean isAvailable(IJavaElement javaElement) throws JavaModelException { if (javaElement == null) return false; if (! javaElement.exists()) return false; if (javaElement.isReadOnly()) return false; // work around for https://bugs.eclipse.org/bugs/show_bug.cgi?id=48422 // the Java project is now cheating regarding its children so we shouldn't // call isStructureKnown if the project isn't open. // see bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=52474 if (!(javaElement instanceof IJavaProject) && !(javaElement instanceof ILocalVariable) && !javaElement.isStructureKnown()) return false; if (javaElement instanceof IMember && ((IMember)javaElement).isBinary()) return false; return true; } public static IType findTypeInPackage(IPackageFragment pack, String elementName) throws JavaModelException { Assert.isTrue(pack.exists()); Assert.isTrue(!pack.isReadOnly()); String packageName= pack.getElementName(); elementName= packageName.length() > 0 ? packageName + '.' + elementName : elementName; return pack.getJavaProject().findType(elementName, (IProgressMonitor) null); } public static RefactoringStatus checkTempName(String newName, IJavaElement context) { RefactoringStatus result= Checks.checkIdentifier(newName, context); if (result.hasFatalError()) return result; if (! Checks.startsWithLowerCase(newName)) result.addWarning(RefactoringCoreMessages.ExtractTempRefactoring_convention); return result; } public static RefactoringStatus checkEnumConstantName(String newName, IJavaElement context) { RefactoringStatus result= Checks.checkFieldName(newName, context); if (result.hasFatalError()) return result; for (int i= 0; i < newName.length(); i++) { char c= newName.charAt(i); if (Character.isLetter(c) && !Character.isUpperCase(c)) { result.addWarning(RefactoringCoreMessages.RenameEnumConstRefactoring_convention); break; } } return result; } public static RefactoringStatus checkConstantName(String newName, IJavaElement context) { RefactoringStatus result= Checks.checkFieldName(newName, context); if (result.hasFatalError()) return result; for (int i= 0; i < newName.length(); i++) { char c= newName.charAt(i); if (Character.isLetter(c) && !Character.isUpperCase(c)) { result.addWarning(RefactoringCoreMessages.ExtractConstantRefactoring_convention); break; } } return result; } public static boolean isException(IType iType, IProgressMonitor pm) throws JavaModelException { try{ if (! iType.isClass()) return false; IType[] superTypes= iType.newSupertypeHierarchy(pm).getAllSupertypes(iType); for (int i= 0; i < superTypes.length; i++) { if ("java.lang.Throwable".equals(superTypes[i].getFullyQualifiedName())) //$NON-NLS-1$ return true; } return false; } finally{ pm.done(); } } /** * @param e * @return int * Checks.IS_RVALUE if e is an rvalue * Checks.IS_RVALUE_GUESSED if e is guessed as an rvalue * Checks.NOT_RVALUE_VOID if e is not an rvalue because its type is void * Checks.NOT_RVALUE_MISC if e is not an rvalue for some other reason */ public static int checkExpressionIsRValue(Expression e) { if(e instanceof Name) { if(!(((Name) e).resolveBinding() instanceof IVariableBinding)) { return NOT_RVALUE_MISC; } } ITypeBinding tb= e.resolveTypeBinding(); boolean guessingRequired= false; if (tb == null) { guessingRequired= true; tb= ASTResolving.guessBindingForReference(e); } if (tb == null) return NOT_RVALUE_MISC; else if (tb.getName().equals("void")) //$NON-NLS-1$ return NOT_RVALUE_VOID; return guessingRequired ? IS_RVALUE_GUESSED : IS_RVALUE; } public static boolean isDeclaredIn(VariableDeclaration tempDeclaration, Class astNodeClass) { ASTNode initializer= ASTNodes.getParent(tempDeclaration, astNodeClass); if (initializer == null) return false; ASTNode anonymous= ASTNodes.getParent(tempDeclaration, AnonymousClassDeclaration.class); if (anonymous == null) return true; // stupid code. Is to find out if the variable declaration isn't a field. if (ASTNodes.isParent(anonymous, initializer)) return false; return true; } }